﻿using System;
using System.Threading;

namespace NsbExtensions.Utilities
{
    public enum AccessType
    {
        Read,
        Write
    }

    public class LockHelper : IDisposable
    {
        private readonly ReaderWriterLock _lock;
        private AccessType _access;
        private LockCookie _lockCookie;

        public LockHelper(ReaderWriterLock rwLock, AccessType access, TimeSpan timeout)
        {
            _lock = rwLock;
            _access = access;

            if (_access == AccessType.Read)
                _lock.AcquireReaderLock(timeout);
            else
                _lock.AcquireWriterLock(timeout);
        }

        #region IDisposable Members

        public void Dispose()
        {
            if (_lock == null)
                return;

            if (_access == AccessType.Read)
                _lock.ReleaseReaderLock();
            else
                _lock.ReleaseWriterLock();
        }

        #endregion

        public void UpgradeAccessToWrite(TimeSpan timeout)
        {
            if (_access == AccessType.Read)
            {
                _lockCookie = _lock.UpgradeToWriterLock(timeout);
                _access = AccessType.Write;
            }
        }

        public void DowngradeAccessToRead()
        {
            if (_access == AccessType.Write)
            {
                _lock.DowngradeFromWriterLock(ref _lockCookie);
                _access = AccessType.Read;
            }
        }
    }

    public class ReaderLock : LockHelper
    {
        public ReaderLock(ReaderWriterLock rwLock, TimeSpan timeout) : base(rwLock, AccessType.Read, timeout)
        {
        }
    }

    public class WriterLock : LockHelper
    {
        public WriterLock(ReaderWriterLock rwLock, TimeSpan timeout) : base(rwLock, AccessType.Write, timeout)
        {
        }
    }
}